package cn.sunshine.ymcc.service.impl;

import cn.sunshine.ymcc.config.SmsCodeProperties;
import cn.sunshine.ymcc.constant.CommonExceptionEnum;
import cn.sunshine.ymcc.constant.RedisConstant;
import cn.sunshine.ymcc.domain.MessageSms;
import cn.sunshine.ymcc.dto.RedisSMSCodeValueDTO;
import cn.sunshine.ymcc.dto.SmsCodeDTO;
import cn.sunshine.ymcc.exception.GlobleException;
import cn.sunshine.ymcc.result.JSONResult;
import cn.sunshine.ymcc.service.IMessageSmsService;
import cn.sunshine.ymcc.service.IVerifycodeService;
import cn.sunshine.ymcc.util.AssertUtil;
import cn.sunshine.ymcc.util.StrUtils;
import cn.sunshine.ymcc.util.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @Author: Eric
 * @CreateTime: 2022-08-06  10:32
 * @Description: TODO
 */
@Service
@Slf4j
public class VerifycodeServiceImpl implements IVerifycodeService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private SmsCodeProperties smsCodeProperties;

    @Autowired
    private IMessageSmsService iMessageSmsService;

    //@Value("${smscode.expire}")
    //private Long expire;
    //@Value("${smscode.interval}")
    //private Long interval;

    /*
       1.判断参数(手机号,图形验证码,key)
	   2.生成code(抽成一个方法)
	    是否已经存在redis中
	        2.1存在
	            判断时间戳
	            2.1.1如果在规定的时间内发的请求  那么需要抛异常
				2.1.2如果不在时间内  返回这个code
	        2.2不存在
	            2.2.1生成smsCode()
	   3.存放在redis中-->调用短信发送的工具类(自己写)
	   4.存db(t_message_sms)
	存db()
     */
    @Override
    public JSONResult sendSmsCode(SmsCodeDTO dto) {
        //1.判断参数(手机号,图形验证码,key)
        //1.1 图片验证码校验
        //如果校验失败 应该抛异常'
        boolean checkImgCode = checkImgCode(dto);
        AssertUtil.isTrue(checkImgCode,
                CommonExceptionEnum.IMG_CODE_ERROR.getMessage(),
                CommonExceptionEnum.IMG_CODE_ERROR.getCode());
        //生成code然后再装到对象里面
        RedisSMSCodeValueDTO redisSMSCodeValueDTO = generateSmsCode(dto);
        String redisKey = RedisConstant.REDIS_SMS_CODE_PREFIX + dto.getMobile();
        redisTemplate.opsForValue().set(redisKey, redisSMSCodeValueDTO, smsCodeProperties.getExpire(), TimeUnit.MINUTES);
        //发送消息
        String message = sendSMSCode(redisSMSCodeValueDTO.getCode(), dto.getMobile());
        insertSMSSendLog(dto, message);
        return JSONResult.success();
    }


    /**
     * 短信发送日志存入DB
     * <p>
     * code   title
     * code---->title
     */
    private void insertSMSSendLog(SmsCodeDTO dto, String message) {
        //创建消息实体类
        MessageSms messageSms = new MessageSms();
        messageSms.setTitle("用户注册短信验证码");
        messageSms.setContent(message);
        //获取ip地址 start
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest httpServletRequest = servletRequestAttributes.getRequest();
        messageSms.setIp(httpServletRequest.getRemoteAddr());
        //获取ip地址 end
        messageSms.setSendTime(new Date());
        iMessageSmsService.insert(messageSms);
        log.info("=======================================");
        log.info(messageSms.getId().toString());
    }


    /**
     * 图片验证码校验
     */
    private boolean checkImgCode(SmsCodeDTO dto) {
        //TODO 完善图片验证码校验
        //假装   你图形验证码  如果写的是111111
        //我就认为是错的
      /*  if (StringUtils.equals("111111", imgCode)) {
            return false;
        }
        return true;*/
        String imgCode = redisTemplate.opsForValue().get(dto.getImageCodeKey()).toString();
        System.out.println(imgCode);
        System.out.println(dto.getImageCode());
        AssertUtil.isTrue(StringUtils.equalsIgnoreCase(imgCode,dto.getImageCode()),"你填个验证码都填不对吗？");
        return true;


    }


    /*
    生成手机验证码

    是否已经存在redis中
	        2.1存在
	            判断时间戳
	            2.1.1如果在规定的时间内发的请求  那么需要抛异常
				2.1.2如果不在时间内  返回这个code
	        2.2不存在
	            2.2.1生成smsCode()
     */
    private RedisSMSCodeValueDTO generateSmsCode(SmsCodeDTO dto) {
        //现在只有一个手机号
        //redis 生成的规则:
        //REDIS_SMS_CODE:13838389438
        String redisKey = RedisConstant.REDIS_SMS_CODE_PREFIX + dto.getMobile();
        RedisSMSCodeValueDTO redisSMSCodeValueDTO = (RedisSMSCodeValueDTO) redisTemplate.opsForValue().get(redisKey);
        //如果redisKey不存在
        if (redisSMSCodeValueDTO == null) {
            redisSMSCodeValueDTO = new RedisSMSCodeValueDTO(StrUtils.getComplexRandomString(4), new Date());
            return redisSMSCodeValueDTO;
        }
        //---------------------
        Date createDate = redisSMSCodeValueDTO.getCreateDate();

        //规定间隔时间是1分钟
        if ((System.currentTimeMillis() - createDate.getTime()) / 1000 < smsCodeProperties.getInterval()) {
            throw new GlobleException("不要着急");
        } else {
            return redisSMSCodeValueDTO;
        }
        //------------------------

    }


    private String sendSMSCode(String code, String mobie) {
        //TODO 调用发送消息的工具
        log.info("你丫的手机号是(" + mobie + ")拿去你的验证码" + code);
        return "你丫的手机号是(" + mobie + ")拿去你的验证码" + code;
    }

    /*
     * @Title: sendimageCode
     * @Description: 图形验证码校验
     * @Author: Mr.Jiang
     * @Version: 1.0
     * @Date:  2022/8/7 22:09
     * @Parameters: [key]
     * @Return cn.sunshine.ymcc.result.JSONResult
     */
    @Override
    public String sendimageCode(String key) {
        // 判断传递的参数是否为空，为空就抛出异常
        if (org.springframework.util.StringUtils.isEmpty(key)) {
            throw new GlobleException("请传递正确的参数");
        }
        // 使用字符串工具类生成4位随机码
        String code = StrUtils.getComplexRandomString(4);
        // 将4位随机字符串存到Redis中并设置过期时间5分钟
        redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES);
        // 将生成的随机字符串生成图形并编码成base64
        String base64Str = VerifyCodeUtils.verifyCode(100, 35, code);
        return base64Str;
    }
}
